package yb.ecp.fast.user.service;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.Ref;
import yb.ecp.fast.infra.util.StringUtil;
import yb.ecp.fast.user.dao.entity.*;
import yb.ecp.fast.user.dao.mapper.*;
import yb.ecp.fast.user.infra.ErrorCode;
import yb.ecp.fast.user.service.VO.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by john on 2017/11/25.
 */
@Service
public class MenuService {
    @Autowired
    MenuMapper menuMapper;

    @Autowired
    ProfileMapper profileMapper;

    @Autowired
    RoleMenuMapper roleMenuMapper;
    @Autowired
    RoleMapper roleMapper;

    @Autowired
    ProfileService profileService;

    @Autowired
    private WorkspaceMapper workspaceMapper;

    @Autowired
    private TemplateService templateService;
    @Autowired
    private TmpMenuMapper tmpMenuMapper;
    @Autowired
    private TmpAuthMapper tmpAuthMapper;

    @Autowired
    private MenuCacheService menuCacheService;

    /**
     * 查询用户所在企业对于的权限模板所拥有的菜单集合（树形菜单）
     *
     * @param userId String
     * @return List<MenuDisplayVO>
     */
    public List<MenuDisplayVO> getShownMenuTree(String userId) {
        LogHelper.monitor("getShownMenuTree调用queryAuthTemplateId");
        Ref<String> templateIdRef = new Ref<>("");
        ErrorCode queryCode = profileService.queryAuthTemplateId(userId, templateIdRef);
        if (queryCode != ErrorCode.Success) {
            return new ArrayList<>();
        }
        AuthorizedQueryParamCache paramCache=menuCacheService.queryAuthorizedQueryParamCache();
        return getMenuTreeV2(0, true, templateIdRef.get(), null, paramCache);
    }

    /**
     * 查询该平台的菜单集合
     *
     * @param site Integer
     * @return List
     */
    public List<MenuDisplayVO> listShownMenu(Integer site) {
        List<MenuDO> menuDOList = menuMapper.getDisplayedList(site);
        List<MenuDisplayVO> menuDisplayVOList = new ArrayList<>();
        for (MenuDO menuDO : menuDOList) {
            MenuDisplayVO menuDisplayVO = new MenuDisplayVO();
            BeanUtils.copyProperties(menuDO, menuDisplayVO);
            menuDisplayVOList.add(menuDisplayVO);
        }
        return menuDisplayVOList;
    }

    /**
     * 根据用户ID获取对应工作空间的按钮ID集合
     *
     * @param userId String
     * @return List
     */
    public List<Integer> tempMenusByUserId(String userId) {
        ProfileDO profileDO = profileMapper.selectById(userId);

        if (null == profileDO) {
            return new ArrayList<>();
        }

        WorkspaceDO workspaceDO = workspaceMapper.selectById(profileDO.getSpaceId());

        if (null == workspaceDO) {
            return new ArrayList<>();
        }

        List<Integer> tempMenuIds = templateService.queryMenuByTemplate(workspaceDO.getTempId());

        return tempMenuIds;
    }


    /**
     * templateId和site只会传一个值<br >
     * templateId不空则查询模板对应的菜单集合<br>
     * site不空则查询site对应的菜单集合
     *
     * @param parentId   Integer 上级菜单id
     * @param showFlag   boolean
     * @param templateId String 权限模板ID
     * @param site       Integer
     * @return List
     */
    private List<MenuDisplayVO> getMenuTree(Integer parentId, boolean showFlag, String templateId, Integer site) {
        if (parentId == null) {
            parentId = 0;
        }

        List<MenuDisplayVO> menuDisplayVOList = new ArrayList<>();
        List<MenuDO> menuDOList;

        //查询菜单菜单
        menuDOList = getChildrenByParentId(parentId, templateId, site);

        for (MenuDO menuDO : menuDOList) {
            MenuDisplayVO menuDisplayVO = new MenuDisplayVO();
            BeanUtils.copyProperties(menuDO, menuDisplayVO);
            menuDisplayVOList.add(menuDisplayVO);
        }

        for (MenuDisplayVO menuDisplayVO : menuDisplayVOList) {
            List<MenuDisplayVO> childrenMenuList = getMenuTree(menuDisplayVO.getId(), showFlag, templateId, site);
            menuDisplayVO.setChildren(childrenMenuList);
        }
        setMenuListWithAuth(menuDisplayVOList, templateId);
        return menuDisplayVOList;
    }


    /**
     * templateId和site只会传一个值<br >
     * templateId不空则查询模板对应的菜单集合<br>
     * site不空则查询site对应的菜单集合
     *
     * @param parentId   Integer 上级菜单id
     * @param showFlag   boolean
     * @param templateId String 权限模板ID
     * @param site       Integer
     * @return List
     */
    private List<MenuDisplayVO> getMenuTreeV2(Integer parentId, boolean showFlag, String templateId, Integer site, final AuthorizedQueryParamCache paramCache) {
        if (parentId == null) {
            parentId = 0;
        }

        List<MenuDisplayVO> menuDisplayVOList = new ArrayList<>();
        List<MenuDO> menuDOList;
        //查询菜单菜单
        menuDOList = getChildrenByParentIdV2(parentId, templateId, site, paramCache);

        for (MenuDO menuDO : menuDOList) {
            MenuDisplayVO menuDisplayVO = new MenuDisplayVO();
            BeanUtils.copyProperties(menuDO, menuDisplayVO);
            menuDisplayVOList.add(menuDisplayVO);
        }

        for (MenuDisplayVO menuDisplayVO : menuDisplayVOList) {
            List<MenuDisplayVO> childrenMenuList = getMenuTreeV2(menuDisplayVO.getId(), showFlag, templateId, site, paramCache);
            menuDisplayVO.setChildren(childrenMenuList);
        }
        setMenuListWithAuthV2(menuDisplayVOList, templateId, paramCache);
        return menuDisplayVOList;
    }

    /**
     * @param menuDisplayVOList
     */
    private void setMenuListWithAuth(List<MenuDisplayVO> menuDisplayVOList, String tempId) {
        if (!StringUtil.isNullOrSpace(tempId)) {
            for (MenuDisplayVO menuDisplayVO : menuDisplayVOList) {
                menuDisplayVO.setAuths(getMenuAuthListByTemp(menuDisplayVO.getId(), tempId));
            }
        } else {
            for (MenuDisplayVO menuDisplayVO : menuDisplayVOList) {
                menuDisplayVO.setAuths(getMenuAuthListBySite(menuDisplayVO.getId()));
            }
        }
    }


    /**
     * setMenuListWithAuth改造，数据从外部传入参数中获取，不再自己去查数据库
     *
     * @param menuDisplayVOList
     */
    private void setMenuListWithAuthV2(List<MenuDisplayVO> menuDisplayVOList, String tempId, final AuthorizedQueryParamCache paramCache) {
        if (!StringUtil.isNullOrSpace(tempId)) {
            for (MenuDisplayVO menuDisplayVO : menuDisplayVOList) {
                menuDisplayVO.setAuths(getMenuAuthListByTempV2(menuDisplayVO.getId(), tempId, paramCache));
            }
        } else {
            for (MenuDisplayVO menuDisplayVO : menuDisplayVOList) {
                menuDisplayVO.setAuths(getMenuAuthListBySiteV2(menuDisplayVO.getId(), paramCache));
            }
        }
    }

    /**
     * 查询权限模板下按钮对应的权限
     *
     * @param menuId Integer
     * @param tempId String
     * @return List<AuthVO>
     */
    private List<AuthVO> getMenuAuthListByTemp(Integer menuId, String tempId) {
        List<AuthVO> authList = new ArrayList<>();

        //根据menu查询所有对应的权限
        List<AuthDO> authDOs = menuMapper.selectAuthListByMenu(menuId);
        List<Integer> tempAuths = templateService.queryAuthByTemplate(tempId);

        for (AuthDO authDO : authDOs) {
            if (!tempAuths.contains(authDO.getAuthId())) {
                continue;
            }
            AuthVO authVO = new AuthVO();
            BeanUtils.copyProperties(authDO, authVO);
            authVO.setParentId(menuId);
            authList.add(authVO);
        }
        return authList;
    }


    /**
     * 查询权限模板下按钮对应的权限
     *
     * @param menuId Integer
     * @param tempId String
     * @return List<AuthVO>
     */
    private List<AuthVO> getMenuAuthListByTempV2(Integer menuId, String tempId, final AuthorizedQueryParamCache paramCache) {
        List<AuthVO> authList = new ArrayList<>();

        //根据menu查询所有对应的权限
        Map<String, List<AuthDO>> menuidGroupMenuAuths = paramCache.getMenuidGroupMenuAuths();
        List<AuthDO> authDOs = menuidGroupMenuAuths.get(menuId.toString()) == null ?
                Collections.EMPTY_LIST : menuidGroupMenuAuths.get(menuId.toString());

        Map<String, List<TmpAuthDO>> tmpIdGroupTmpAuth = paramCache.getTmpIdGroupTmpAuth();
        List<TmpAuthDO> tmpAuthDOS = tmpIdGroupTmpAuth.get(tempId) == null ?
                Collections.EMPTY_LIST : tmpIdGroupTmpAuth.get(tempId);
        List<Integer> tempAuths = tmpAuthDOS.stream().map(TmpAuthDO::getAuthId).collect(Collectors.toList());

        for (AuthDO authDO : authDOs) {
            if (!tempAuths.contains(authDO.getAuthId())) {
                continue;
            }
            AuthVO authVO = new AuthVO();
            BeanUtils.copyProperties(authDO, authVO);
            authVO.setParentId(menuId);
            authList.add(authVO);
        }
        return authList;
    }


    /**
     * 查询按钮对应的权限集合
     * getMenuAuthListBySite 改造，不走数据库都，从传参中获取
     *
     * @param menuId Integer
     * @return List<AuthVO>
     */
    private List<AuthVO> getMenuAuthListBySiteV2(Integer menuId, final AuthorizedQueryParamCache paramCache) {
        List<AuthVO> authList = new ArrayList<>();
        Map<String, List<AuthDO>> menuidGroupMenuAuths = paramCache.getMenuidGroupMenuAuths();
        List<AuthDO> authDOs = menuidGroupMenuAuths.get(menuId.toString());

        for (AuthDO authDO : authDOs) {
            AuthVO authVO = new AuthVO();
            BeanUtils.copyProperties(authDO, authVO);
            authVO.setParentId(menuId);
            authList.add(authVO);
        }
        return authList;
    }

    /**
     * 查询按钮对应的权限集合
     *
     * @param menuId Integer
     * @return List<AuthVO>
     */
    private List<AuthVO> getMenuAuthListBySite(Integer menuId) {
        List<AuthVO> authList = new ArrayList<>();

        //根据menu查询所有对应的权限
        List<AuthDO> authDOs;
        authDOs = menuMapper.selectAuthListByMenu(menuId);

        for (AuthDO authDO : authDOs) {
            AuthVO authVO = new AuthVO();
            BeanUtils.copyProperties(authDO, authVO);
            authVO.setParentId(menuId);
            authList.add(authVO);
        }
        return authList;
    }

    /**
     * 根据按钮查所有权限集合
     *
     * @return List
     */
    public List<MenuAuthListVO> getAuthListByMenu(String userId) {
        List<MenuAuthListVO> menuAuthList = new ArrayList<>();
        List<AuthVO> authList;
        List<AuthDO> authDOs;
        MenuAuthListVO menuAuth;
        AuthVO authVO;
        List<Integer> tempAuthIds;
        List<Integer> menuIdList;

        //        //查询所有menu集合
        //        List<Integer> menuIdList = menuMapper.listDisplayMenuId();


        TemplateVO templateVO = templateService.queryTempByUserId(userId);

        if (null == templateVO) {
            return new ArrayList<>();
        }
        menuIdList = templateService.queryMenuByTemplate(templateVO.getId());
        tempAuthIds = templateService.queryAuthByTemplate(templateVO.getId());


        for (Integer menuId : menuIdList) {
            menuAuth = new MenuAuthListVO();
            authList = new ArrayList<>();

            //根据menu查询所有对应的权限
            authDOs = menuMapper.selectAuthListByMenu(menuId);

            for (AuthDO authDO : authDOs) {
                if (!tempAuthIds.contains(authDO.getAuthId())) {
                    continue;
                }
                authVO = new AuthVO();
                BeanUtils.copyProperties(authDO, authVO);
                authList.add(authVO);
            }

            menuAuth.setMenuId(menuId);
            menuAuth.setAuths(authList);

            menuAuthList.add(menuAuth);
        }
        return menuAuthList;
    }

    /**
     * 根据用户ID查询auth集合信息
     *
     * @param userId String
     * @return List
     */
    public List<AuthVO> listAuthByUser(String userId) {
        List<AuthDO> authDOList;
        Set<AuthVO> authVOSet = new HashSet<>();
        AuthVO authVO;
        List<AuthVO> result = new ArrayList<>();

        List<String> roleIds;

        TemplateVO templateVO = templateService.queryTempByUserId(userId);

        List<Integer> tempAuthIds = templateService.queryAuthByTemplate(templateVO.getId());

        //查询角色集合
        roleIds = roleMapper.selectRoleIdsByUserId(userId);

        //查询权限集合

        for (String roleId : roleIds) {
            authDOList = menuMapper.selectAuthListByRole(roleId);

            //遍历权限DO集合，封装VO
            for (AuthDO authDO : authDOList) {
                if (!tempAuthIds.contains(authDO.getAuthId())) {
                    continue;
                }
                authVO = new AuthVO();
                BeanUtils.copyProperties(authDO, authVO);
                authVOSet.add(authVO);
            }
        }
        result.addAll(authVOSet);
        return result;
    }

    /**
     * @param tmpId
     * @return
     */
    public ErrorCode removeByTemplate(String tmpId) {


        return ErrorCode.Success;
    }

    /**
     * 查询site最大按钮集合
     *
     * @param site
     * @return
     */
    public List<Integer> queryMenuIdsBySite(Integer site) {
        List<Integer> menuIds = menuMapper.selectBySite(site);

        return menuIds;
    }


    /**
     * 查询角色集合对应的权限集合（去重）
     *
     * @param roleIds List
     * @return List
     */
    private List<AuthVO> queryAuthsByRoleIds(List<String> roleIds) {
        List<AuthDO> authDOList;
        List<AuthVO> authVOList = new ArrayList<>();
        Set<AuthVO> authVOSet = new HashSet<>();


        for (String roleId : roleIds) {
            authDOList = menuMapper.selectAuthListByRole(roleId);

            //遍历权限DO集合，封装VO
            for (AuthDO authDO : authDOList) {
                AuthVO authVO = new AuthVO();
                BeanUtils.copyProperties(authDO, authVO);
                authVOSet.add(authVO);
            }
        }
        authVOList.addAll(authVOSet);

        return authVOList;
    }

    /**
     * 根据角色ID集合查询对接的权限code集合
     *
     * @param roleIds List
     * @return List
     */
    public List<Integer> queryAuthIdsByRoleIds(List<String> roleIds) {
        List<Integer> authIds = new ArrayList<>();
        Set<Integer> authIdSet = new HashSet<>();

        for (String roleId : roleIds) {
            List<Integer> authList = roleMapper.queryAuthIdsByRoleId(roleId);
            authIdSet.addAll(authList);
        }
        authIds.addAll(authIdSet);

        return authIds;
    }


    /**
     * 查询配置页面菜单列表
     *
     * @return List
     */
    public List<MenuDisplayVO> listMenuBySite(Integer site) {
        Integer parentId = 0;
        List<MenuDisplayVO> menuDisplayVOList = new ArrayList<>();

        List<MenuDO> menuDOList = menuMapper.queryListMenuForConfig(parentId, site);

        for (MenuDO menuDO : menuDOList) {
            MenuDisplayVO menuDisplayVO = new MenuDisplayVO();
            BeanUtils.copyProperties(menuDO, menuDisplayVO);
            List<MenuDisplayVO> menuDisplayVOs = getMenuTree(menuDisplayVO.getId(), true, null, site);
            menuDisplayVO.setChildren(menuDisplayVOs);
            menuDisplayVOList.add(menuDisplayVO);
        }

        setMenuListWithAuth(menuDisplayVOList, null);
        return menuDisplayVOList;
    }

    //通过外部传menu,tmppMenu数据，不用在走一遍数据库
    private List<MenuDO> getChildrenByParentIdV2(Integer parentId, String templateId, Integer site, AuthorizedQueryParamCache paramCache) {
        List<MenuDO> allMenuDOs = paramCache.getParentGroupMenuesMap().get(Long.valueOf(parentId));
        if (allMenuDOs == null) {
            return Collections.EMPTY_LIST;
        }
        List<Integer> menuIds;
        if (!StringUtil.isNullOrEmpty(templateId)) {
            List<TmpMenuDO> tmpMenuDOS = paramCache.getTmpIdGroupTmpMenuesMap().get(templateId);
            menuIds = tmpMenuDOS == null ? Collections.EMPTY_LIST : tmpMenuDOS.stream().map(TmpMenuDO::getMenuId).collect(Collectors.toList());
        } else if (null != site) {
            List<MenuDO> menuDOS = paramCache.getSiteGroupMenuesMap().get(site);
            menuIds = menuDOS == null ? Collections.EMPTY_LIST :
                    menuDOS.stream().map(MenuDO::getId).collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }

        List<MenuDO> menuDOs = new ArrayList<>();

        for (MenuDO menuDO : allMenuDOs) {
            if (menuIds.contains(menuDO.getId())) {
                menuDOs.add(menuDO);
            }
        }
        return menuDOs;
    }


    private List<MenuDO> getChildrenByParentId(Integer parentId, String templateId, Integer site) {
        List<MenuDO> allMenuDOs = menuMapper.getChildList(parentId);

        List<Integer> menuIds;

        if (!StringUtil.isNullOrEmpty(templateId)) {
            menuIds = templateService.queryMenuByTemplate(templateId);
        } else if (null != site) {
            menuIds = queryMenuIdsBySite(site);
        } else {
            return new ArrayList<>();
        }

        List<MenuDO> menuDOs = new ArrayList<>();

        for (MenuDO menuDO : allMenuDOs) {
            if (menuIds.contains(menuDO.getId())) {
                menuDOs.add(menuDO);
            }
        }
        return menuDOs;
    }
}
